﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Graphics = System.Drawing.Graphics;
using Bitmap = System.Drawing.Bitmap;
using OpenFileDialog = System.Windows.Forms.OpenFileDialog;
namespace grafika4_1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial  class MainWindow : Window
    {
        private int moveIndex;
        private FilterFunction filterFunction;
        private Stack<WriteableBitmap> stackWritableBitmaps;  
        private WriteableBitmap writeableBitmap;
        public MainWindow()
        {
            InitializeComponent();
           stackWritableBitmaps=new Stack<WriteableBitmap>(3);
        }


#region EVENTS
        private void radioButton_Checked(object sender, RoutedEventArgs e)
        {
            RadioButton radioButton = (RadioButton) sender;
            if (((string)radioButton.Content) == "Jasność")
                filterFunction = ChangeBrightnes;
            else if (((string)radioButton.Content) == "Kontrast")
                filterFunction = ChangeContrast;
            else if (((string)radioButton.Content) == "Własny")
                filterFunction = ChangeOwn;
                
        }
        private void chbBrush_Checked(object sender, RoutedEventArgs e)
        {
           
            
        }
        private void btnChoseWallPaper_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Multiselect = false;
            openFileDialog.Filter = "JPG Files (*.jpg)|*.jpg|Bitmap Files (*.bmp)|*.bmp|PNG Files (*.png)|*.png|GIF Files (*.gif)|*.gif";
            if(openFileDialog.ShowDialog()==System.Windows.Forms.DialogResult.OK)
            {
                LoadPicture(openFileDialog.FileName);
            }
        }



        private void btnBackImage_Click(object sender, RoutedEventArgs e)
        {
            if(stackWritableBitmaps.Count==0)
                return;
            WriteableBitmap w = stackWritableBitmaps.Pop();
            image.ImageSource = w;
            writeableBitmap = w;
        }

        

        private void btnBrightness_Click(object sender, RoutedEventArgs e)
        {

        }


        private void workSpace_MouseMove(object sender, MouseEventArgs e)
        {
            Point point = e.GetPosition(workSpace);
            point.X -= rectangle.ActualWidth/2;
            point.Y -= rectangle.ActualHeight/2;
            if (rectangle.Width + point.X >= workSpace.ActualWidth || rectangle.Height + point.Y > workSpace.ActualHeight)
                return;
                
            Canvas.SetLeft(rectangle,point.X);
            Canvas.SetTop(rectangle,point.Y);
            if(e.LeftButton==MouseButtonState.Pressed)
            {
                if (moveIndex % 10 == 0)
                {
                    ChangeRect(e.GetPosition(workSpace));
                    moveIndex = 0;
                }
                moveIndex++;
            }

        }

        private void workSpace_MouseEnter(object sender, MouseEventArgs e)
        {

            rectangle.Visibility = Visibility.Visible;
        }

        private void workSpace_MouseLeave(object sender, MouseEventArgs e)
        {
            rectangle.Visibility = Visibility.Hidden;
        }
        private void workSpace_MouseDown(object sender, MouseButtonEventArgs e)
        {

            stackWritableBitmaps.Push(writeableBitmap.Clone());
            if(chbBrush.IsChecked==false)
            {
                ChangeAllWorkSpace();
                return;
            }
           ChangeRect(e.GetPosition(workSpace));
          
        }
#endregion
#region METHODS
        private void ChangeRect(Point p)
        {
            p.X -= rectangle.ActualWidth / 2;
            p.Y -= rectangle.ActualHeight / 2;
            for (int i = 0; i < rectangle.ActualWidth; i++)
            {

                for (int j = 0; j < rectangle.ActualHeight; j++)
                {
                    Point point = new Point(p.X + i, p.Y + j);
                    if (point.X  > workSpace.ActualWidth || point.Y  > workSpace.ActualHeight||point.Y<=0||point.X<0)
                        continue;
                    filterFunction(point);
                }
            }
        }
        public static T DeepClone<T>(T obj)
        {
            using (var ms = new MemoryStream())
            {
                var formatter = new BinaryFormatter();
                formatter.Serialize(ms, obj);
                ms.Position = 0;

                return (T)formatter.Deserialize(ms);
            }
        }
        private void LoadPicture(String path)
        {

            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.UriSource = new Uri(path);
            bi.DecodePixelWidth = (int)workSpace.ActualWidth;
            bi.DecodePixelHeight = (int)workSpace.ActualHeight;
            bi.EndInit();



            writeableBitmap = new WriteableBitmap(bi);
            image.ImageSource = writeableBitmap;

        }
        private void LoadPicture(Image image)
        {
            
        }
        private void ChangeOwn(Point point)
        {
            Color color = GetColorFromImage(point);
            int R = color.R;
            int G = color.G;
            int B = color.B;
            int tmp = B;
            B = G;
            G = R;
            R = tmp;

            //R =(int)( R*.393 + G*.769 + B*.189);
            //G = (int) (R*.349 + G*.686 + B*.168);
            //B = (int) (R*.272 + G*.534 + B*.131);
            //if (R < 0) R = 0;
            //else if (R > 255) R = 255;
            //if (G < 0) G = 0;
            //else if (B > 255) G = 255;
            //if (B < 0) B = 0;
            //else if (B > 255) B = 255;

            DrawPixel(point,Color.FromRgb((byte)R,(byte)G,(byte)B));
        }
       private void ChangeBrightnes(Point point)
       {
           int brightnes = int.Parse(txtBrightnes.Text);
           Color c = GetColorFromImage(point);
           

           int r =(brightnes+ c.R);
           if (r > 255) r = 255;
           else if (r < 0) r = 0;
           int g =  (brightnes + c.G);
           if (g > 255) g = 255;
           else if (g < 0) g = 0;
           int b =  (brightnes + c.B);
           if (b > 255) b = 255;
           else if (b < 0) b = 0;
           Color newColor = Color.FromArgb(c.A,(byte) r,(byte) g,(byte) b);
          
           DrawPixel(point,newColor);


       }
        private void ChangeContrast(Point point)
        {
            int contrast = int.Parse(txtContrast.Text);
            contrast -= 128;
            double d = 0.0;
            if (contrast >= 0 && contrast <= 127)
            {
                d = (double)127 / (double)(127 - contrast);
            }
            else if (contrast < 0)
            {
                d = (double)(127 + contrast) / (double)127;
            }
            Color color = GetColorFromImage(point);
            int r = color.R;
            int g = color.G;
            int b = color.B;
            r = (int) (d*(r - contrast));
            if (r < 0) r = 0;
            else if (r > 255) r = 255;
            g = (int) (d*(g - contrast));
            if (g < 0) g = 0;
            else if (g > 255) g = 255;
            b = (int) (d*(g - contrast));
            if (b < 0) b = 0;
            else if (b > 255) b = 255;

            Color c = Color.FromArgb(color.A, (byte) r, (byte) g, (byte) b);
            DrawPixel(point,c);
        }
       private void DrawPixel(Point point,Color color)
       {
           writeableBitmap.Lock();
           unsafe
           {
               int pBackBuffer = (int)writeableBitmap.BackBuffer;
               pBackBuffer += (int)point.Y * writeableBitmap.BackBufferStride;
               pBackBuffer += (int)point.X* 4;
               int color_data = color.R << 16; // R
               color_data |= color.G << 8;   // G
               color_data |= color.B << 0;   // B
               *((int*)pBackBuffer) = color_data;
           }
           writeableBitmap.AddDirtyRect(new Int32Rect((int)point.X,(int)point.Y, 1, 1));
           writeableBitmap.Unlock();
       }
        private Color GetColorFromImage(Point point)
        {
            IntPtr buff = writeableBitmap.BackBuffer;
            int Stride = writeableBitmap.BackBufferStride;
            Color c;
            unsafe
            {
            byte* pbuff = (byte*)buff.ToPointer();
            int loc = (int)point.Y * Stride + (int)point.X * 4;
            c=Color.FromArgb(pbuff[loc+3],
            pbuff[loc+2],pbuff[loc+1],
            pbuff[loc]);
            }
            return c;
        }
        private void ChangeAllWorkSpace()
        {
            
            for(int i=0;i<workSpace.ActualWidth;i++)
            {
                for(int j=0;j<workSpace.ActualHeight;j++)
                {
                    filterFunction(new Point(i, j));
                }
            }
        }

       

       
#endregion

        

      
    }

    public delegate void FilterFunction(Point point);
}
